/*
 *
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "stdafx.h"
#include "../client/DCPlusPlus.h"
#include "../client/SimpleXML.h"
#include "../client/Pointer.h"

#include "AGEmotionSetup.h"
#include <math.h>

#include "../GdiOle/GDIImageOle.h"

CAGEmotion::CAGEmotion() : m_EmotionBmp(NULL), m_ImagePos(-1), m_bMaySupportAnimation(false), m_pGifImage(NULL)
{
}

CAGEmotion::~CAGEmotion()
{
	if (m_pGifImage)
		m_pGifImage->Release();
}

CImageList* CAGEmotion::m_pImagesList = NULL;
bool CAGEmotion::Create(const tstring& strEmotionText, const string& strEmotionBmpPath, const string& strEmotionGifPath)
{
	if (strEmotionBmpPath.size())
	{
		m_EmotionBmp = (HBITMAP) ::LoadImage(0, Text::toT(strEmotionBmpPath).c_str(), IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
		
		if (m_EmotionBmp)
			m_BmpImageObject.SetBitmap(m_EmotionBmp);
	}
	
	if (!g_isWineCheck && strEmotionGifPath.size())
	{
		m_bMaySupportAnimation = true;
		
		// [!] brain-ripper
		// Don't make any initialization here!
		// Any initialization will be done in
		// GetImageObject function, on demand,
		// to save resources and time for users, who don't
		// want use animated icons
	}
	
	if (!m_EmotionBmp && !m_bMaySupportAnimation)
		return false;
		
	m_EmotionText = strEmotionText;
	m_EmotionBmpPath = strEmotionBmpPath;
	if (!g_isWineCheck)
		m_EmotionGifPath = strEmotionGifPath;
		
	return true;
}

CGDIImage *CAGEmotion::getAnimatedImage(HWND hCallbackWnd, DWORD dwCallbackMsg)
{
	if (m_bMaySupportAnimation && !m_pGifImage)
	{
		// Create object and load icon only on demand,
		// to save resources and time for users, who don't
		// want use animated icons
		std::string str = Util::getDataPath();
		str += m_EmotionGifPath;
		
		// N.B. don't delete this object, use Release method!
		m_pGifImage = CGDIImage::CreateInstance(Text::toT(str).c_str(), hCallbackWnd, dwCallbackMsg);
		
		if (!m_pGifImage->IsInited())
		{
			m_pGifImage->Release();
			m_pGifImage = NULL;
			
			m_bMaySupportAnimation = false;
		}
	}
	
	return m_pGifImage;
}

IOleObject *CAGEmotion::GetImageObject(bool bAnimated, IOleClientSite *pOleClientSite, IStorage *pStorage, HWND hCallbackWnd, DWORD dwCallbackMsg, COLORREF BkColor)
{
	IOleObject *pObject = NULL;
	
	if (bAnimated && (m_bMaySupportAnimation || m_pGifImage))
	{
		getAnimatedImage(hCallbackWnd, dwCallbackMsg);
		
		CComObject<CGDIImageOle> *pGifImageObject = NULL;
		if (m_pGifImage)
		{
			// Create view instance of single graphic object (m_pGifImage).
			// Instance will be automatically removed after releasing last pointer;
			CComObject<CGDIImageOle>::CreateInstance(&pGifImageObject);
			
			if (pGifImageObject)
			{
				if (pGifImageObject->put_SetImage(m_pGifImage, BkColor, hCallbackWnd, dwCallbackMsg) != S_OK)
				{
					delete pGifImageObject;
					pGifImageObject = NULL;
					m_bMaySupportAnimation = false;
				}
			}
			else
				m_bMaySupportAnimation = false;
		}
		
		if (pGifImageObject)
		{
			pGifImageObject->QueryInterface(IID_IOleObject, (void**)&pObject);
			pObject->SetClientSite(pOleClientSite);
		}
		else
		{
			if (m_pGifImage)
			{
				m_pGifImage->Release();
				m_pGifImage = NULL;
			}
			m_bMaySupportAnimation = false;
		}
	}
	
	if (!pObject)
	{
		HBITMAP hBitmap = getEmotionBmp(BkColor);
		
		if (hBitmap)
		{
			m_BmpImageObject.SetBitmap(hBitmap);
			pObject = m_BmpImageObject.GetOleObject(pOleClientSite, pStorage);
			
			DeleteObject(hBitmap);
		}
	}
	
	return pObject;
}

HBITMAP CAGEmotion::getEmotionBmp(const COLORREF &clrBkColor)
{
	if ((m_pImagesList == NULL) || (m_ImagePos < 0))
		return NULL;
		
	CBitmap dist;
	CClientDC dc(NULL);
	
	IMAGEINFO ii;
	m_pImagesList->GetImageInfo(getImagePos(), &ii);
	
	int nWidth = ii.rcImage.right - ii.rcImage.left;
	int nHeight = ii.rcImage.bottom - ii.rcImage.top;
	
	dist.CreateCompatibleBitmap(dc, nWidth, nHeight);
	CDC memDC;
	memDC.CreateCompatibleDC(dc);
	HBITMAP pOldBitmap = (HBITMAP) SelectObject(memDC, dist);
	
	memDC.FillSolidRect(0, 0, nWidth, nHeight, clrBkColor);
	m_pImagesList->Draw(memDC, getImagePos(), CPoint(0, 0), ILD_NORMAL);
	
	SelectObject(memDC, pOldBitmap);
	
	return (HBITMAP)dist.Detach();
}

CAGEmotionSetup::~CAGEmotionSetup()
{
	cleanup();
}
void CAGEmotionSetup::cleanup()
{
	for_each(EmotionsList.begin(), EmotionsList.end(), DeleteFunction());
	EmotionsList.clear();
	m_images.Destroy();
	m_CountSelEmotions = 0;
	m_FilterEmotiion.clear();
}
bool CAGEmotionSetup::LoadEmotion(const string& p_file_name)
{
	const string l_fileName = Util::getDataPath() + "EmoPacks\\" + p_file_name + ".xml";
	if ((p_file_name == "Disabled") || !Util::fileExists(l_fileName))
		return true;
		
	try
	{
		SimpleXML xml;
		xml.fromXML(File(l_fileName, File::READ, File::OPEN).read());
		
		if (xml.findChild("Emoticons"))
		{
			xml.stepIn();
			
			string strEmotionText;
			string strEmotionBmpPath;
			string strEmotionGifPath;
			while (xml.findChild("Emoticon"))
			{
				strEmotionText = xml.getChildAttrib("PasteText");
				if (strEmotionText.empty())
					strEmotionText = xml.getChildAttrib("Expression");
				while (strEmotionText[0] == ' ') // ltrim
					strEmotionText.erase(0, 1);
				if (!strEmotionText.empty())
				{
//              dcdebug("CAGEmotionSetup::Create: emotion:[%s]\n", Text::fromT(strEmotionText).c_str());
					if (m_FilterEmotiion.count(strEmotionText))
					{
//                  dcdebug("CAGEmotionSetup::Create: dup emotion:[%s]\n", strEmotionText.c_str());
						continue;
					}
					m_FilterEmotiion.insert(strEmotionText);
					strEmotionBmpPath = xml.getChildAttrib("Bitmap");
					
					// [~] brain-ripper
					// since all smiles in pack provided with relative path,
					// which starts without '.\', I commented out next block
					/*
					if (strEmotionBmpPath.size() > 0)
					{
					    if (strEmotionBmpPath[0] == '.')
					    {
					        // Relativni cesta - dame od aplikace
					        strEmotionBmpPath = Util::getDataPath() + "EmoPacks\\" + strEmotionBmpPath;
					    }
					    else strEmotionBmpPath = "EmoPacks\\" + strEmotionBmpPath;
					}
					*/
					strEmotionBmpPath = "EmoPacks\\" + strEmotionBmpPath;
					strEmotionGifPath = xml.getChildAttrib("Gif");
					
					// [~] brain-ripper
					// since all smiles in pack provided with relative path,
					// which starts without '.\', I commented out next block
					/*
					if (strEmotionGifPath.size() > 0)
					{
					    if (strEmotionGifPath[0] == '.')
					    {
					        // Relativni cesta - dame od aplikace
					        strEmotionGifPath = Util::getDataPath() + "EmoPacks\\" + strEmotionGifPath;
					    }
					    else strEmotionGifPath = "EmoPacks\\" + strEmotionGifPath;
					}
					*/
					if (!strEmotionGifPath.empty())
						strEmotionGifPath = "EmoPacks\\" + strEmotionGifPath;
						
					CAGEmotion* pEmotion = new CAGEmotion();
//[!]PPA for lock bmp
//              File* l__f = new File (Util::getDataPath() + strEmotionBmpPath, File::READ, File::OPEN);
					if (!pEmotion->Create(Text::toT(strEmotionText), strEmotionBmpPath, strEmotionGifPath))
					{
						delete pEmotion;
						continue;
					}
					m_CountSelEmotions++;
					EmotionsList.push_back(pEmotion);
				}
			}
			xml.stepOut();
		}
	}
	catch (const Exception& e)
	{
		dcdebug("CAGEmotionSetup::Create: %s\n", e.getError().c_str());
		return false;
	}
	return true;
}
bool CAGEmotionSetup::InitImages()
{
	CAGEmotion::setImageList(0);
	if (!m_images.Create(18, 18, ILC_COLORDDB | ILC_MASK, 0, 1))
	{
		dcassert(FALSE);
		return false;
	}
	CAGEmotion::setImageList(&m_images);
	CDC oTestDC;
	if (!oTestDC.CreateCompatibleDC(NULL))
		return FALSE;
	for (CAGEmotion::Iter pEmotion = EmotionsList.begin(); pEmotion != EmotionsList.end(); ++pEmotion)
	{
		HBITMAP hBmp = (*pEmotion)->getEmotionBmp();
		if (hBmp)
		{
			HBITMAP poPrevSourceBmp = (HBITMAP) SelectObject(oTestDC, hBmp);
			COLORREF clrTransparent = GetPixel(oTestDC, 0, 0);
			SelectObject(oTestDC, poPrevSourceBmp);
			int nImagePos = m_images.Add(hBmp, clrTransparent);
			(*pEmotion)->setImagePos(nImagePos);
			DeleteObject(hBmp);
		}
	}
	return true;
}
bool CAGEmotionSetup::Create()
{
	setUseEmoticons(false);
	cleanup();
	const string l_CurentName = SETTING(EMOTICONS_FILE);
	if (l_CurentName == "Disabled")
		return true;
	LoadEmotion(l_CurentName); //[+]PPA
	const int l_cntMain = m_CountSelEmotions;
	WIN32_FIND_DATA data;
	HANDLE hFind;
	hFind = FindFirstFile(Text::toT(Util::getDataPath() + "EmoPacks\\*.xml").c_str(), &data);
	if (hFind != INVALID_HANDLE_VALUE)
	{
		do
		{
			string l_name = Text::fromT(data.cFileName);
			string::size_type i = l_name.rfind('.');
			l_name = l_name.substr(0, i);
			if (l_CurentName != l_name)
				LoadEmotion(l_name);
		}
		while (FindNextFile(hFind, &data));
		FindClose(hFind);
	}
	m_CountSelEmotions = l_cntMain;
	InitImages();
	setUseEmoticons(true);
	return true;
}
